package com.iocup.keybastion.core;

import com.iocup.keybastion.authorize.DefaultAuthorizer;
import com.iocup.keybastion.authorize.decision.HasAuthorizationDecision;
import com.iocup.keybastion.authorize.decision.RequiresUserDecision;
import com.iocup.keybastion.authorize.Authorizer;
import com.iocup.keybastion.authorize.decision.HasPermissionDecision;
import com.iocup.keybastion.authorize.decision.HasRoleDecision;
import com.iocup.keybastion.authorize.element.ConfigFileElementProvider;
import com.iocup.keybastion.configuration.*;

import com.iocup.keybastion.core.client.ClientFinder;
import com.iocup.keybastion.core.client.LocalTokenBaseClient;
import com.iocup.keybastion.core.impl.DefaultLoginChecker;
import com.iocup.keybastion.core.impl.DefaultSecurityLogicChecker;
import com.iocup.keybastion.core.impl.DefaultLoginLogic;
import com.iocup.keybastion.core.impl.DefaultLogoutLogic;
import com.pine.sunflower.core.LifeCycledAdapter;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author xyjxust
 * @create 2022/3/2 17:35
 **/
@Slf4j
public class SecurityEngine extends LifeCycledAdapter {

    private static final String version = "0.1";

    private List<SecurityConfiguratorAdapter> securityConfiguratorAdapters = new ArrayList<>();
    @Getter
    private AuthenticationConfigurator authenticationConfigurator = new AuthenticationConfigurator();
    @Getter
    private AuthorizationConfigurator authorizationConfigurator = new AuthorizationConfigurator();
    @Getter
    private HttpConfigurator httpConfigurator = new HttpConfigurator();
    @Getter
    private Authorizer authorizer;

    @Getter
    private SecurityLogicChecker securityLogicChecker;

    @Getter
    private DefaultLoginLogic loginLogic;

    @Getter
    private LogoutLogic logoutLogic;


    public SecurityEngine securityConfiguratorAdapter(SecurityConfiguratorAdapter... securityConfiguratorAdapter) {
        securityConfiguratorAdapters.addAll(Arrays.asList(securityConfiguratorAdapter));
        return this;
    }

    public SecurityEngine securityConfiguratorAdapter(List<SecurityConfiguratorAdapter> securityConfiguratorAdapter) {
        securityConfiguratorAdapters.addAll(securityConfiguratorAdapter);
        return this;
    }


    @SneakyThrows
    @Override
    public void doInit() {
        initConfig();
        initAuthorizationConfig();
        initCoreLogic();
        println();
    }

    @Override
    public void doStop() {


    }


    /**
     * 初始化核心逻辑器
     */
    private void initCoreLogic() {
//        //路由匹配检查器
//        matchingLogicChecker = new DefaultMatchingLogicChecker()
//                .matchingChecker(this.httpSecurity.getMatchingChecker())
//                .httpActionAdapter(this.httpSecurity.getHttpActionAdapter());
        //初始化认证逻辑检查器
        securityLogicChecker = new DefaultSecurityLogicChecker(this.getAuthenticationConfigurator().getMatchingChecker())
                .addChecker(this.authenticationConfigurator.getPreCheckers().toArray(new SecurityPreLogicChecker[]{}))
                .addChecker(new DefaultLoginChecker(this.authenticationConfigurator.getClientFinder(), this.authenticationConfigurator.getSecurityProperties()))
                .addChecker(this.authenticationConfigurator.getPostCheckers().toArray(new SecurityPostLogicChecker[]{}));

        //初始化本地token客户端
        LocalTokenBaseClient client = new LocalTokenBaseClient();
        client.setTokenExtractProperties(this.authenticationConfigurator.getTokenExtractProperties());
        client.setTokenService(this.authenticationConfigurator.getTokenService());
        this.authenticationConfigurator.addClient(client);

        ClientFinder clientFinder = this.authenticationConfigurator.getClientFinder();

//        //认证逻辑检测器初始化
//        this.authLogicChecker = new DefaultAuthLogicChecker(clientFinder).addExclude(this.matchingProperties.getExcludeList().toArray(new String[]{}))
//                .addInclude(this.matchingProperties.getIncludeList().toArray(new String[]{}));
        //登录逻辑初始化
        this.loginLogic = new DefaultLoginLogic(this.authenticationConfigurator.getAuthenticators());
        this.loginLogic.setTokenProperties(this.authenticationConfigurator.getTokenProperties());
        this.loginLogic.setTokenExtractProperties(this.authenticationConfigurator.getTokenExtractProperties());
        this.loginLogic.setTokenService(this.authenticationConfigurator.getTokenService());
        //登出逻辑初始化
        this.logoutLogic = new DefaultLogoutLogic(clientFinder, this.authenticationConfigurator.getSecurityProperties());
    }


    /**
     * 初始化权限配置
     */
    private void initAuthorizationConfig() {
        //添加默认的权限决断器
        this.authorizationConfigurator.addDecision(this.authenticationConfigurator.getBasicAuthDecision());
        this.authorizationConfigurator.addDecision(new RequiresUserDecision());
        this.authorizationConfigurator.addDecision(new HasRoleDecision(this.authorizationConfigurator.getHasAuthorizationProvider()));
        this.authorizationConfigurator.addDecision(new HasPermissionDecision(this.authorizationConfigurator.getHasAuthorizationProvider()));
        this.authorizationConfigurator.addDecision(new HasAuthorizationDecision(this.authorizationConfigurator.getHasAuthorizationProvider()));
        //添加配置文件权限提供器
        ConfigFileElementProvider configFileElementProvider = new ConfigFileElementProvider();
        configFileElementProvider.getElementStore().put(this.authorizationConfigurator.getPermissionProperties().getPermissions());
        //权限检查器
        authorizer = new DefaultAuthorizer().authDecisionFinder(this.authorizationConfigurator.getAuthDecisionFinder())
                .authElementService(this.authorizationConfigurator.getAuthElementService()
                        .addProvider(configFileElementProvider)
                        //添加注解的权限元数据提供器
                        .addProvider(this.authorizationConfigurator.getAuthAnnotationParser().getAuthElementProvider()));
    }


    /**
     * 初始化配置文件中的信息
     */
    private void initConfig() {
        if (securityConfiguratorAdapters.isEmpty()) {
            securityConfiguratorAdapters.add(new DefaultSecurityConfiguratorAdapter());
        }
        securityConfiguratorAdapters.forEach(securityConfiguratorAdapter -> {
            securityConfiguratorAdapter.configure(this.authenticationConfigurator);
            securityConfiguratorAdapter.configure(this.authorizationConfigurator);
            securityConfiguratorAdapter.configure(this.httpConfigurator);
        });
        if(this.authenticationConfigurator.getSecurityProperties()==null){
            this.authenticationConfigurator.securityProperties(new SecurityProperties());
        }
        //默认拦截所有请求
        this.authenticationConfigurator.getSecurityProperties().getIncludeList().add("/**");
        //默认不拦截登录地址
        this.authenticationConfigurator.getSecurityProperties().getExcludeList().add("/login");

    }


    private void println() {
        System.out.println("                                 .__  __          \n" +
                "  ______ ____   ____  __ _________|__|/  |_ ___.__.\n" +
                " /  ___// __ \\_/ ___\\|  |  \\_  __ \\  \\   __<   |  |\n" +
                " \\___ \\\\  ___/\\  \\___|  |  /|  | \\/  ||  |  \\___  |\n" +
                "/____  >\\___  >\\___  >____/ |__|  |__||__|  / ____|\n" +
                "     \\/     \\/     \\/                       \\/     ");
        log.info("安全认证服务启动完毕");
    }
}
